package com.nami.store.biz.conver.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.TimeInterval;
import com.nami.store.api.request.conversation.ConverItem;
import com.nami.store.api.request.conversation.ConverPageReq;
import com.nami.store.api.response.conversation.ConversationDTO;
import com.nami.store.api.response.conversation.ConverDetailVO;
import com.nami.store.api.response.group.GroupDTO;
import com.nami.store.api.response.message.MessageDTO;
import com.nami.store.biz.cache.service.CacheConverDomainService;
import com.nami.store.biz.conver.bo.ConverZAddValue;
import com.nami.store.biz.conver.convert.ConverConvert;
import com.nami.store.biz.conver.repository.ConverRepository;
import com.nami.store.biz.conver.service.ConverDomainService;
import com.nami.store.biz.group.repository.GroupRepository;
import com.nami.store.biz.grphismsgs.repository.GrpHisMsgsRepository;
import com.nami.store.biz.privatehismsgs.repository.PrivateHisMsgsRepository;
import com.nami.store.biz.user.convert.UserConvert;
import com.nami.store.biz.user.repository.UserRepository;
import com.nami.store.domain.ConversationDO;
import com.nami.store.domain.UserDO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.enums.conver.ConverTypeIntEnum;
import org.dromara.common.json.utils.JsonUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Service
@RequiredArgsConstructor
public class ConverDomainServiceImpl implements ConverDomainService {

    private final ConverRepository converRepository;

    private final CacheConverDomainService cacheRepository;

    private final UserRepository userRepository;

    private final GroupRepository groupRepository;

    private final PrivateHisMsgsRepository privateMsgRepository;

    private final GrpHisMsgsRepository grpHisMsgsRepository;


    @Override
    public ConversationDTO getConverFromCacheOrDB(String appKey, String userId, String targetId) {
        ConverItem item = cacheRepository.get(appKey, userId, targetId);
        if (item == null) {
            ConversationDO conversation = converRepository.getConversation(appKey, userId, targetId);
            if (conversation == null) {
                return null;
            }
            cacheRepository.writeConverItem(ConverConvert.INSTANCE.convert5(conversation));
            return ConverConvert.INSTANCE.convert(conversation);
        }
        return ConverConvert.INSTANCE.convert4(item);
    }

    @Override
    public boolean batchSave(List<ConversationDO> convers) {
        return converRepository.batchSave(convers);
    }

    @Override
    public boolean insertOrUpd(ConversationDO conver) {
        return converRepository.insertOrUpd(conver);
    }

    @Override
    public List<ConversationDTO> getConversFromCacheOrDB(String appKey, List<String> userIds, String targetId) {
        TimeInterval timer = DateUtil.timer();
        List<ConverItem> cacheList = cacheRepository.getConversByGrpView(appKey, userIds, targetId);
        if (CollUtil.isNotEmpty(cacheList)) {
            if (cacheList.size() == userIds.size()) {
                return ConverConvert.INSTANCE.convertList4(cacheList);
            }
            List<ConversationDTO> cacheConvers = ConverConvert.INSTANCE.convertList4(cacheList);
            List<String> cacheUserIds = cacheList.stream().map(ConverItem::getUserId).collect(Collectors.toList());
//            userId.removeAll(cacheUserIds);
            List<String> qryIds = userIds.stream().filter(item -> !cacheUserIds.contains(item)).collect(Collectors.toList());
            List<ConversationDO> dbConvers = converRepository.getConversByUserIds(appKey, qryIds, targetId);
            if (CollUtil.isNotEmpty(dbConvers)) {
                cacheRepository.writeAll(ConverConvert.INSTANCE.convertList5(dbConvers));
                cacheConvers.addAll(ConverConvert.INSTANCE.convertList(dbConvers));
                return cacheConvers;
            }

        }
        List<ConversationDO> conversByUserIds = converRepository.getConversByUserIds(appKey, userIds, targetId);
        if (CollUtil.isNotEmpty(conversByUserIds)) {
            cacheRepository.writeAll(ConverConvert.INSTANCE.convertList5(conversByUserIds));
        }
        if (timer.interval() > 300) {
            log.warn("[conver-batch] 批量获取缓存出现问题， appKey={}, targetId={} use:{}ms", appKey, targetId, timer.interval());
        }

        return ConverConvert.INSTANCE.convertList(conversByUserIds);
    }

    @Override
    public boolean batchUpdConvers(List<ConverItem> itemList) {
        List<ConversationDO> conversations = ConverConvert.INSTANCE.converList2(itemList);
//        Set<Conversation> addList = conversations.stream().filter(item -> item.getId() == null).collect(Collectors.toSet());
//        conversationService.batchSave(addList);
//        List<Conversation> updList = conversations.stream().filter(item -> item.getId() != null).collect(Collectors.toList());
        return converRepository.batchUpdConvers(conversations);
    }

    @Override
    public TableDataInfo<ConverDetailVO> getConvers(ConverPageReq request) {
        TimeInterval timer = DateUtil.timer();
        log.info("[conver] 分页获取会话 request={}", JsonUtils.toJsonString(request));
        ConverZAddValue converPage = cacheRepository.getConverPage(request);
        if (converPage.getSize() == 0) {
            return TableDataInfo.build(new ArrayList<>());
        }

        List<String> targetIds = converPage.getTargetIds();
        if (CollUtil.isEmpty(targetIds)) {
            return TableDataInfo.build(new ArrayList<>());
        }
        List<String> cacheKeys = new ArrayList<>();
        for (String targetId : targetIds) {
            cacheKeys.add(request.getUserId() + "_" + targetId);
        }
        List<ConverItem> originalConvers = cacheRepository.getConverFromKeys(request.getAppKey(), request.getUserId(), cacheKeys);
//        List<ConversationDO> originalConvers = converRepository.getConversByUserIds(request.getAppKey(), request.getUserId(), targetIds);

        List<String> c2cMsgIds = originalConvers.stream()
            .filter(item -> ConverTypeIntEnum.C2C.getCode() == item.getConverType())
            .map(ConverItem::getLatestMsgId).collect(Collectors.toList());

        List<String> grpMsgIds = originalConvers.stream()
            .filter(item -> ConverTypeIntEnum.C2G.getCode() == item.getConverType())
            .map(ConverItem::getLatestMsgId).collect(Collectors.toList());

        Map<String, MessageDTO> c2cMap = privateMsgRepository.getMsgs(c2cMsgIds);
        Map<String, MessageDTO> grpMsgMap = grpHisMsgsRepository.getMsgs(grpMsgIds);

        List<String> targetUserIds = originalConvers.stream()
            .filter(item -> ConverTypeIntEnum.C2C.getCode() == (item.getConverType()))
            .map(ConverItem::getTargetId)
            .collect(Collectors.toList());
        Map<String, UserDO> userMap = userRepository.getUsers(targetUserIds);

        List<String> groupIds = originalConvers.stream()
            .filter(item -> ConverTypeIntEnum.C2G.getCode() == (item.getConverType()))
            .map(ConverItem::getTargetId)
            .collect(Collectors.toList());
        Map<String, GroupDTO> groupMap = groupRepository.getGroupMap(groupIds);

        List<ConverDetailVO> details = new ArrayList<>(originalConvers.size());
        ConverDetailVO item = null;
        for (ConverItem originalConver : originalConvers) {
            item = new ConverDetailVO();
            if (ConverTypeIntEnum.C2G.getCode() == (originalConver.getConverType())) {
                GroupDTO groupDTO = groupMap.get(originalConver.getTargetId());
                if (groupDTO != null) {
                    item.setGroup(groupDTO);
                }
                MessageDTO messageVO = grpMsgMap.get(originalConver.getLatestMsgId());
                item.setMessage(messageVO);
            } else {
                UserDO userDO = userMap.get(originalConver.getTargetId());
                if (userDO != null) {
                    item.setTargetUser(UserConvert.INSTANCE.convert(userDO));
                }

                MessageDTO messageVO = c2cMap.get(originalConver.getLatestMsgId());
                item.setMessage(messageVO);
            }

            item.setAppKey(originalConver.getAppKey());
            item.setUserId(originalConver.getUserId());
            item.setTargetId(originalConver.getTargetId());
            item.setIfMute(originalConver.getIfMute());
            item.setLatestMsgId(originalConver.getLatestMsgId());
            item.setLatestReadMsgIndex(originalConver.getLatestReadMsgIndex());
            item.setLatestReadMsgTime(originalConver.getLatestReadMsgTime());
            item.setLatestUnreadMsgIndex(originalConver.getLatestUnreadMsgIndex());
//            item.setUnreadTag(originalConver.getUnreadTag());
            item.setSortTime(originalConver.getSortTime());
            item.setSyncTime(originalConver.getSyncTime());
            item.setConverType(originalConver.getConverType());

            details.add(item);
        }
        List<ConverDetailVO> finalConvers = details.stream()
            .sorted((o1, o2) -> o2.getSortTime().compareTo(o1.getSortTime()))
            .collect(Collectors.toList());
        TableDataInfo<ConverDetailVO> build = TableDataInfo.build(finalConvers);
        build.setTotal(converPage.getSize());
        if (timer.interval() > 200) {
            log.warn("[conver] 获取分页会话 出现慢查询 use={}ms", timer.interval());
        }
        return build;
    }

    @Override
    public ConverItem getConverFromCache(String appKey, String userId, String targetId) {
        return cacheRepository.get(appKey, userId, targetId);
    }

}
